/******************************************************************************
 * @file    Charlieplexing_hal.c
 * @author  赵子恒 3393018959@qq.com 公众号：子恒笔记
 * @version V1.0
 * @date    2025-05-06
 * @brief   Charlieplexing HAL implementation for PY32F030xx.
 ******************************************************************************
 ******************************************************************************
 */
#include "Charlieplexing.h"

static uint8_t led_bit_maps[8] = {0};

const uint8_t smg_val_maps[] = {
	0xFC, // 0
	0x60, // 1
	0xDA, // 2
	0xF2, // 3
	0x66, // 4
	0xB6, // 5
	0xBE, // 6
	0xE0, // 7
	0xFE, // 8
	0xF6  // 9
};

const uint8_t smg_id_maps[4][7] = {
	{23, 24, 25, 26, 27, 28, 29},
	{16, 17, 18, 19, 20, 21, 22},
	{7, 8, 9, 10, 11, 12, 13},
	{0, 1, 2, 3, 4, 5, 6}};

void api_charlieplexing_set_bit(uint8_t led_id, uint8_t led_state)
{
	uint8_t pbit = led_id & 0x07;
	uint8_t pbyte = led_id >> 3;
	if (led_id >= HAL_LED_ID_MAX)
		return;
	if (led_state)
		led_bit_maps[pbyte] |= (1 << pbit);
	else
		led_bit_maps[pbyte] &= ~(1 << pbit);
}

//单颗循环扫描，一次调用只扫描一颗led
//需要较高的扫描周期，led亮度均匀，led亮度低
void api_charlieplexing_mode0_callback(void)
{
	static uint8_t led_id = 0xff;
	uint8_t pbit = led_id & 0x07;
	uint8_t pbyte = led_id >> 3;

	hal_charlieplexing_led_id_set(led_id, LED_OFF);

	led_id++;
	if (led_id >= HAL_LED_ID_MAX)
		led_id = 0;

	pbit = led_id & 0x07;
	pbyte = led_id >> 3;

	if (!(led_bit_maps[pbyte] & (1 << pbit)))
	{
		hal_charlieplexing_led_id_set(led_id, LED_OFF);
	}
	else
	{
		hal_charlieplexing_led_id_set(led_id, LED_ON);
	}
}

//共阴扫描，调用周期较低，一次扫描一组led，若io灌电流足够，则相对于单颗扫描可以获取较大亮度
//可以点亮更多的led，但亮度均匀性较差，若led压降相对不一致，则会有的灯较亮，有的灯较暗
void api_charlieplexing_mode1_callback(void)
{
	static uint8_t cur_com_low_gpio_id = 0xff;
	
	//当前所有io高阻，消影
	hal_charlieplexing_gpio_all_highz();
	
	cur_com_low_gpio_id++;
	if(cur_com_low_gpio_id >= HAL_GPIO_ID_MAX){
		cur_com_low_gpio_id = 0;
	}
	
	//扫描30个灯
	for(uint8_t led_id = 0; led_id < HAL_LED_ID_MAX; led_id++)
	{
		//找出当前共阴极的所有led
		hal_gpio_id_t higt_id = hal_find_com_low_gpio_id(cur_com_low_gpio_id, led_id);
		if(higt_id != HAL_GPIO_ID_MAX)
		{
			//获取显存状态，设置当前共阴极下led的阳极状态
			uint8_t pbit = led_id & 0x07;
			uint8_t pbyte = led_id >> 3;
			if (!(led_bit_maps[pbyte] & (1 << pbit))){
				hal_charlieplexing_gpio_id_set(higt_id, HIGH_Z);
			}else{
				hal_charlieplexing_gpio_id_set(higt_id, OUTPUT_1);
			}
		}
	}
	hal_charlieplexing_gpio_id_set(cur_com_low_gpio_id, OUTPUT_0);
}

//共阳扫描，同上
void api_charlieplexing_mode2_callback(void)
{
	static uint8_t cur_com_higt_gpio_id = 0xff;
	
	hal_charlieplexing_gpio_all_highz();
	
	cur_com_higt_gpio_id++;
	if(cur_com_higt_gpio_id >= HAL_GPIO_ID_MAX){
		cur_com_higt_gpio_id = 0;
	}
	
	for(uint8_t led_id = 0; led_id < HAL_LED_ID_MAX; led_id++)
	{
		hal_gpio_id_t low_id = hal_find_com_higt_gpio_id(cur_com_higt_gpio_id, led_id);
		if(low_id != HAL_GPIO_ID_MAX)
		{
			//获取显存状态，设置当前共阴极下led的阳极状态
			uint8_t pbit = led_id & 0x07;
			uint8_t pbyte = led_id >> 3;
			if (!(led_bit_maps[pbyte] & (1 << pbit))){
				hal_charlieplexing_gpio_id_set(low_id, HIGH_Z);
			}else{
				hal_charlieplexing_gpio_id_set(low_id, OUTPUT_1);
			}
		}
	}
	hal_charlieplexing_gpio_id_set(cur_com_higt_gpio_id, OUTPUT_0);
}

void api_charlieplexing_init(void)
{
	memset(led_bit_maps, 0, 8);
	hal_charlieplexing_init();
}

void api_charlieplexing_test(void)
{
	static uint8_t flg = 1;
	//	extern void LL_mDelay(uint32_t Delay);
	//
	//	for(uint8_t i = 0; i < HAL_CHARLIEPLEXING_LEDS_NUM; i++)
	//	{
	//		api_charlieplexing_set_bit(i-1,0);
	//		api_charlieplexing_set_bit(i,1);
	//		LL_mDelay(2000);
	//	}

	api_smg_set_val(0, 0);
	LL_mDelay(10000);
	api_smg_set_val(1111, 0);
	LL_mDelay(10000);
	api_smg_set_val(2222, 1);
	LL_mDelay(10000);
	api_smg_set_val(3333, 0);
	LL_mDelay(10000);
	api_smg_set_val(4444, 1);
	LL_mDelay(10000);
	api_smg_set_val(5555, 0);
	LL_mDelay(10000);
	api_smg_set_val(6666, 1);
	LL_mDelay(10000);
	api_smg_set_val(7777, 0);
	LL_mDelay(10000);
	api_smg_set_val(8888, 1);
	LL_mDelay(10000);
	api_smg_set_val(9999, 1);
	LL_mDelay(10000);
}

void api_smg_set_val(uint32_t val, uint8_t colon_flg)
{
	for (uint8_t i = 0; i < 4; i++)
	{
		uint8_t digit = val % 10;
		val /= 10;
		uint8_t unit_val = smg_val_maps[digit];
		for (uint8_t j = 0; j < 7; j++)
		{
			uint8_t bitv = unit_val & (0x80 >> j);
			api_charlieplexing_set_bit(smg_id_maps[i][j], !!bitv);
		}
	}
	api_charlieplexing_set_bit(14, !!colon_flg);
	api_charlieplexing_set_bit(15, !!colon_flg);
}
